package org.xm.sk.service.data.impl;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.xm.sk.dao.ActivityRepository;
import org.xm.sk.vo.e.ActivityStatus;
import org.xm.sk.vo.ob.PageConf;
import org.xm.sk.vo.tb.Activity;
import org.xm.sk.vo.tb.Hairdresser;

@Service
@Transactional
public class ActivityServiceImpl extends BaseServiceImpl<Activity> {

    private static final String CACHE_KEY = "'activity'";
    private static final String sk_CACHE_NAME = "activitys";

    @Autowired
    private ActivityRepository activityRepository;

    @Cacheable(value = sk_CACHE_NAME, key = CACHE_KEY + "'_'+#p0")
    public Activity findById(int id) {
        return this.activityRepository.getOne(id);
    }

    @Cacheable(value = sk_CACHE_NAME, key = CACHE_KEY + "'_'+#p0")
    public Set<Activity> findByName(String name) {
        return this.activityRepository.findByName(name);
    }

    @Cacheable(value = sk_CACHE_NAME, key = CACHE_KEY + "'_all'")
    public List<Activity> findAll() {
        return this.activityRepository.findAll();
    }

    @Cacheable(value = sk_CACHE_NAME, key = CACHE_KEY + "'_'+#p0")
    public List<Activity> findAll(Activity activity) {
        ExampleMatcher matcher = ExampleMatcher.matching();
        Example<Activity> ex = Example.of(activity, matcher);
        return this.activityRepository.findAll(ex);
    }

    @Cacheable(value = sk_CACHE_NAME, key = CACHE_KEY + "'_'+#p0")
    public Object findAllByPage(PageConf pageConf) {
        List<Order> orders = new ArrayList<Order>();
        if (null != pageConf.getSortNames()) {
            for (int i = 0; i < pageConf.getSortNames().size(); i++) {
                orders.add(new Order(pageConf.getSortOrders().get(i),
                        pageConf.getSortNames().get(i)));
            }
        } else {
            orders.add(new Order(Direction.DESC, "id"));
        }
        Sort sort = Sort.by(orders);
        Pageable pageable = null;
        Specification<Activity> querySpecifi = new Specification<Activity>() {

            private static final long serialVersionUID = 4960665487051031079L;

            @Override
            public Predicate toPredicate(Root<Activity> root,
                    CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
                Predicate predicate = cb.and(
                        cb.equal(root.get("datalevel").as(Integer.class), 0));
                List<Predicate> predicates = new ArrayList<>();
                if (null != pageConf.getDataMap()
                        && !pageConf.getDataMap().isEmpty()) {
                    if (null != pageConf.getDataMap().get("startline")
                            || null != pageConf.getDataMap().get("deadline")) {
                        try {
                            SimpleDateFormat sdf = new SimpleDateFormat(
                                    "yyyy-MM-dd");
                            if (null != pageConf.getDataMap()
                                    .get("startline")) {
                                String dateStr = pageConf.getDataMap()
                                        .get("startline").toString();
                                Date date = sdf.parse(dateStr);
                                predicates.add(cb.lessThanOrEqualTo(
                                        root.get("startline").as(Date.class),
                                        date));
                            }
                            if (null != pageConf.getDataMap().get("deadline")) {
                                String dateStr = pageConf.getDataMap()
                                        .get("deadline").toString();
                                Date date = sdf.parse(dateStr);
                                predicates.add(cb.greaterThanOrEqualTo(
                                        root.get("deadline").as(Date.class),
                                        date));
                            }
                        } catch (ParseException e) {
                            e.printStackTrace();
                        }
                    }
                    if (null != pageConf.getDataMap().get("hairdresserId")) {
                        Integer hairdresserId = Integer.valueOf(pageConf.getDataMap().get("hairdresserId").toString());
                        if (0 < hairdresserId) {
                            Join<Activity, Hairdresser> joinHairdresser = root.join("hairdresser",
                                    JoinType.LEFT);
                            predicates.add(cb.equal(joinHairdresser.get("id").as(Integer.class), hairdresserId));
                        } else if (0 == hairdresserId)
                            predicates.add(cb.isNotNull(root.get("hairdresser").as(Hairdresser.class)));
                        else 
                            predicates.add(cb.isNull(root.get("hairdresser").as(Hairdresser.class)));
                    }
                    if (null != pageConf.getDataMap().get("status")
                            && 0 < pageConf.getDataMap().get("status").toString().length()
                            && null != ActivityStatus.valueOf(
                                    pageConf.getDataMap().get("status").toString())) {
                        ActivityStatus status = ActivityStatus
                                .valueOf(pageConf.getDataMap().get("status").toString());
                        predicates.add(cb.equal(
                                root.get("status").as(ActivityStatus.class),
                                status));
                    }
                    // and到一起的话所有条件就是且关系，or就是或关系
                    return cb.and(
                            cb.and(predicates.toArray(
                                    new Predicate[predicates.size()])),
                            predicate);
                } else if (null != pageConf.getSearch()
                        && 0 < pageConf.getSearch().trim().length()) {
                    String search = pageConf.getSearch().trim();
                    // 模糊查找
                    predicates.add(cb.like(root.get("name").as(String.class),
                            "%" + search + "%"));
                    predicates.add(
                            cb.like(root.get("conditions").as(String.class),
                                    "%" + search + "%"));
                    predicates.add(
                            cb.like(root.get("creatorName").as(String.class),
                                    "%" + search + "%"));
                    predicates.add(
                            cb.like(root.get("editerName").as(String.class),
                                    "%" + search + "%"));
                    predicates.add(cb.like(root.get("name").as(String.class),
                            "%" + search + "%"));
                    predicates.add(cb.like(root.get("scope").as(String.class),
                            "%" + search + "%"));
                    predicates
                            .add(cb.like(root.get("deadline").as(String.class),
                                    "%" + search + "%"));
                    predicates.add(
                            cb.like(root.get("modifydate").as(String.class),
                                    "%" + search + "%"));
                    predicates.add(cb.like(root.get("count").as(String.class),
                            "%" + search + "%"));
                    predicates.add(cb.like(root.get("price").as(String.class),
                            "%" + search + "%"));
                    // and到一起的话所有条件就是且关系，or就是或关系
                    return cb.and(
                            cb.or(predicates
                                    .toArray(new Predicate[predicates.size()])),
                            predicate);
                }
                return predicate;
            }
        };
        if (null != pageConf.getPage() && null != pageConf.getSize())
            pageable = PageRequest.of(pageConf.getPage(), pageConf.getSize(),
                    sort);
        if (null != pageable)
            return this.activityRepository.findAll(querySpecifi, pageable);
        else
            return this.activityRepository.findAll(querySpecifi, sort);
    }

    @Cacheable(value = sk_CACHE_NAME, key = CACHE_KEY + "'_'+#p0+'_'+#p1")
    public Object findAllByPage(PageConf pageConf, Object object) {
        return null;
    }

    @CacheEvict(value = sk_CACHE_NAME, allEntries = true)
    // @CachePut(value = sk_CACHE_NAME, key = CACHE_KEY + "'_'+#p0.id")
    public Activity update(Activity activity) {
        activity.setEditer(user().getUserid());
        activity.setEditerName(user().getUsername());
        activity.setModifydate(new Date());
        return this.activityRepository.save(activity);
    }

    @CacheEvict(value = sk_CACHE_NAME, allEntries = true)
    public void delete(int id) {
        this.activityRepository.delete(id, user().getUserid(),
                user().getUsername());
    }

    @CacheEvict(value = sk_CACHE_NAME, allEntries = true)
    public void delete(Set<Integer> ids) {
        this.activityRepository.delete(ids, user().getUserid(),
                user().getUsername());
    }

    @CacheEvict(value = sk_CACHE_NAME, allEntries = true)
    public Activity add(Activity activity) {
        activity.setCreator(user().getUserid());
        activity.setEditer(user().getUserid());
        activity.setCreatorName(user().getUsername());
        activity.setEditerName(user().getUsername());
        return this.activityRepository.saveAndFlush(activity);
    }

}
